package vip.ola.manage.sys.ctrl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import vip.ola.core.common.Exception.ServiceException;
import vip.ola.core.common.annotation.MethodLog;
import vip.ola.core.common.constant.Constant;
import vip.ola.core.common.constant.MchConstant;
import vip.ola.core.common.constant.RetEnum;
import vip.ola.core.common.domain.BizResponse;
import vip.ola.core.common.domain.MenuTreeBuilder;
import vip.ola.core.common.domain.PayResponse;
import vip.ola.core.common.util.*;
import vip.ola.core.entity.SysConfig;
import vip.ola.core.entity.SysLog;
import vip.ola.core.entity.SysResource;
import vip.ola.core.entity.SysUser;
import vip.ola.manage.common.ctrl.BaseController;
import vip.ola.manage.common.service.RpcCommonService;
import vip.ola.manage.secruity.JwtAuthenticationRequest;
import vip.ola.manage.sys.service.SysUserService;

import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static vip.ola.core.common.constant.CacheKey.MGR_TOKEN;
import static vip.ola.core.common.constant.CacheKey.TOKEN_TIMEOUT;
import static vip.ola.core.common.constant.Constant.*;
import static vip.ola.core.common.constant.RetEnum.*;

@RequestMapping(Constant.MGR_CONTROLLER_ROOT_PATH)
@RestController
public class AuthController extends BaseController {

    private static final MyLog _log = MyLog.getLog(AuthController.class);

    @Value("${jwt.cookie}")
    private String tokenCookie;

    @Value("${jwt.expiration}")
    private Integer expiration;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private RpcCommonService rpcCommonService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;




    /**
     * 登录鉴权
     *
     * @return
     * @throws AuthenticationException
     */
    @RequestMapping(value = "/auth")
    @MethodLog(remark = "登录")
    public ResponseEntity<?> auth(HttpServletRequest request,
                                  HttpServletResponse response) throws AuthenticationException {
        String clintIp = IPUtility.getClientIp(request);
//        SysConfig whiteIps = rpcCommonService.rpcSysConfigService.select("code","authLoginIp");
//        if (whiteIps == null || StringUtils.isEmpty(whiteIps.getValue()) || !Arrays.asList(whiteIps.getValue().split("\\,")).contains(clintIp)){
//            return ResponseEntity.ok(new BizResponse(13010, "IP[" + clintIp + "]不允许访问"));
//        }
        JSONObject param = getJsonParam(request);
        String username = getStringRequired(param, "username");
        String password = getStringRequired(param, "password");
        String imgCode = getStringRequired(param, "imgCode");
        Object sessionVerifyCodeObj = request.getSession().getAttribute(LOGIN_VERIFY_CODE);
        String sessionVerifyCode;
        if (Objects.isNull(sessionVerifyCodeObj)) {
            return ResponseEntity.ok(BizResponse.build(RET_COMM_VERIFY_CODE_ERROR));
        }
        sessionVerifyCode = sessionVerifyCodeObj.toString();
        request.getSession().removeAttribute(LOGIN_VERIFY_CODE);
        if (!StringUtils.equalsIgnoreCase(imgCode, sessionVerifyCode)) {
            return ResponseEntity.ok(BizResponse.build(RET_COMM_VERIFY_CODE_ERROR));
        }
        JwtAuthenticationRequest authenticationRequest = new JwtAuthenticationRequest(username, password);
        String token;
        try {
            token = sysUserService.login(authenticationRequest.getUsername(), authenticationRequest.getPassword());
        } catch (ServiceException e) {
            return ResponseEntity.ok(BizResponse.build(e.getRetEnum()));
        }
        SysUser sysUser = rpcCommonService.rpcSysService.findByUserName(username);
        JSONObject data = new JSONObject();
        data.put("access_token", token);
        String googleCodeStr = getString(param, "googleCode");
        if (SECURITY_TYPE_PASS_GOOGLE.equals(sysUser.getLoginSecurityType())) {
//            request.getSession().setAttribute("CODE_TOKEN" + sysUser.getUserId(), token);
//            data.put("userId", sysUser.getUserId());
//            data.put("googleAuth", 1);
            if (StringUtils.isEmpty(googleCodeStr)){
                return ResponseEntity.ok(new BizResponse(13010, "请输入谷歌验证码"));
            }
            long googleCode;
            try {
                googleCode = Long.parseLong(googleCodeStr.trim());
            } catch (Exception e) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_GOOGLECODE_NOT_MATCH));
            }
            // 验证谷歌验证码
            boolean checkResult = checkGoogleCode(sysUser.getGoogleAuthSecretKey(), googleCode);
            if (!checkResult) {
                return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_GOOGLECODE_NOT_MATCH));
            }
        }
        Thread thread = new Thread(() -> {
            SysLog sysLog = new SysLog();
            sysLog.setUserId(sysUser.getUserId());
            sysLog.setCreateTime(new Date());
            sysLog.setSystem((byte) 1);
            sysLog.setMethodName("authLogin");
            sysLog.setUserName(sysUser.getUserName());
            sysLog.setUserIp(clintIp);
            sysLog.setOptReqParam(username+"|"+imgCode+"|"+googleCodeStr);
            sysLog.setOptResInfo("登录成功");
            sysLog.setMethodRemark("authLogin");
            rpcCommonService.rpcSysLogService.add(sysLog);
        });
        thread.start();
//        // 添加cookie
//        Cookie cookie = new Cookie(tokenCookie, token);
//        cookie.setPath("/");
//        cookie.setHttpOnly(true);
//        cookie.setMaxAge(expiration);// 秒
//        response.addCookie(cookie);
        stringRedisTemplate.opsForValue().set(MGR_TOKEN + token, "1", 60 * 60, TimeUnit.SECONDS);
        return ResponseEntity.ok(PayResponse.buildSuccess(data));
    }

    /**
     * google验证
     *
     * @return
     * @throws AuthenticationException
     */
    @RequestMapping(value = "/google_auth")
    public ResponseEntity<?> authGoogle(HttpServletRequest request,
                                        HttpServletResponse response) throws AuthenticationException {
        JSONObject param = getJsonParam(request);
        Long userId = getLongRequired(param, "userId");
        String googleCodeStr = getStringRequired(param, "googleCode").trim();
        long googleCode;
        try {
            googleCode = Long.parseLong(googleCodeStr);
        } catch (Exception e) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_GOOGLECODE_NOT_MATCH));
        }
        SysUser sysUser = rpcCommonService.rpcSysService.findByUserId(userId);
        if (sysUser == null) {
            return ResponseEntity.ok(BizResponse.build(RET_SERVICE_ACCOUNT_NOT_EXIST));
        }
        if (MchConstant.PUB_YES != sysUser.getStatus()) {
            return ResponseEntity.ok(BizResponse.build(RET_MGR_USER_STOP));
        }
        // 验证谷歌验证码
        boolean checkResult = checkGoogleCode(sysUser.getGoogleAuthSecretKey(), googleCode);
        if (!checkResult) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_GOOGLECODE_NOT_MATCH));
        }
        Object token = request.getSession().getAttribute("CODE_TOKEN" + sysUser.getUserId());
        request.getSession().removeAttribute("CODE_TOKEN" + sysUser.getUserId());

//        // 添加cookie
//        Cookie cookie = new Cookie(tokenCookie, token.toString());
//        cookie.setPath("/");
//        cookie.setHttpOnly(false);
//        cookie.setMaxAge(expiration);// 秒
//        response.addCookie(cookie);
        stringRedisTemplate.opsForValue().set(MGR_TOKEN + token, "1", TOKEN_TIMEOUT, TimeUnit.SECONDS);

        JSONObject data = new JSONObject();
        data.put("access_token", token);
        return ResponseEntity.ok(PayResponse.buildSuccess(data));
    }

    /**
     * 刷新token
     *
     * @param request
     * @return
     * @throws AuthenticationException
     */
    @RequestMapping(value = "/refresh")
    public ResponseEntity<?> refreshAndGetAuthenticationToken(
            HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String token = CookieUtil.getCookieByName(request, tokenCookie);
        String refreshedToken;
        try {
            refreshedToken = sysUserService.refreshToken(token);
        } catch (ServiceException e) {
            return ResponseEntity.ok(BizResponse.build(e.getRetEnum()));
        }
        if (refreshedToken == null) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_COMM_OPERATION_FAIL));
        } else {
            JSONObject data = new JSONObject();
            data.put("token", token);
//            // 添加cookie
//            Cookie cookie = new Cookie("token", token);
//            cookie.setPath("/");
//            cookie.setDomain("vip.ola");
//            cookie.setMaxAge(expiration);// 秒
//            response.addCookie(cookie);
            return ResponseEntity.ok(PayResponse.buildSuccess(data));
        }
    }

    /**
     * 修改当前用户登录密码
     *
     * @return
     */
    @RequestMapping("/old_pwd_udseta")
    @ResponseBody
    @MethodLog(remark = "修改密码")
    public ResponseEntity<?> updatePassword(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        // 旧密码
        String oldRawPassword = getStringRequired(param, "oldPassWord");
        // 新密码
        String rawPassword = getStringRequired(param, "passWord");
        // 验证旧密码是否正确
        SysUser sysUser = rpcCommonService.rpcSysService.findByUserId(getUser().getId());
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(oldRawPassword, sysUser.getPassWord())) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_OLDPASSWORD_NOT_MATCH));
        }
        // 判断新密码格式
        if (!StrUtil.checkPassword(rawPassword)) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_PASSWORD_FORMAT_FAIL));
        }
        sysUser = new SysUser();
        sysUser.setUserId(getUser().getId());
        sysUser.setPassWord(encoder.encode(rawPassword));
        sysUser.setLastPasswordResetTime(new Date());
        int count = rpcCommonService.rpcSysService.update(sysUser);
        if (count != 1) ResponseEntity.ok(PayResponse.build(RetEnum.RET_COMM_OPERATION_FAIL));
        return ResponseEntity.ok(BizResponse.buildSuccess());
    }

    /**
     * 查询当前用户信息
     *
     * @return
     */
    @RequestMapping("/current")
    @ResponseBody
    public ResponseEntity<?> current() {
        SysUser sysUser = sysUserService.findByUserId(getUser().getId());
        sysUser.setPassWord(null);
        sysUser.setSuperPassword(null);
        sysUser.setGoogleAuthSecretKey(null);
        return ResponseEntity.ok(PayResponse.buildSuccess(sysUser));
    }

    /**
     * 查询用户菜单
     *
     * @param request
     * @return
     */
    @RequestMapping("/menu")
    @ResponseBody
    public ResponseEntity<?> menu(HttpServletRequest request) {
        List<SysResource> sysResourceList;
        if (MchConstant.PUB_YES == getUser().getIsSuperAdmin()) {
            // 如果是超级管理用户,则得到所有权限资源
            sysResourceList = rpcCommonService.rpcSysService.selectAllResource(SYSTEM_MGR);
        } else {
            // 得到用户的权限资源
            sysResourceList = rpcCommonService.rpcSysService.selectResourceByUserId(getUser().getId());
        }
        List<MenuTreeBuilder.Node> nodeList = new LinkedList<>();
        for (SysResource sysResource : sysResourceList) {
            MenuTreeBuilder.Node node = new MenuTreeBuilder.Node();
            node.setResourceId(sysResource.getResourceId());
            node.setName(sysResource.getName());
            node.setTitle(sysResource.getTitle());
            if (StringUtils.isNotBlank(sysResource.getJump())) node.setJump(sysResource.getJump());
            if (StringUtils.isNotBlank(sysResource.getIcon())) node.setIcon(sysResource.getIcon());
            node.setParentId(sysResource.getParentId());
            nodeList.add(node);
        }
        return ResponseEntity.ok(PayResponse.buildSuccess(JSONArray.parseArray(MenuTreeBuilder.buildTree(nodeList))));
    }

    /**
     * 获取验证码
     */
    @RequestMapping(value = "/auth/auth_code_get")
    public void getAuthCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map randomMap = RandomValidateCodeUtil.getRandcode(120, 40, 6, 20);
        String randomString = randomMap.get("randomString").toString();
        request.getSession().setAttribute(LOGIN_VERIFY_CODE, randomString);
        BufferedImage randomImage = (BufferedImage) randomMap.get("randomImage");
        ImageIO.write(randomImage, "JPEG", response.getOutputStream());
    }


    public static void main(String args[]){
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        System.out.println(encoder.encode("zy123456"));
    }

    @PostMapping("/robotCredit")
    @MethodLog( remark = "商户资金增加" )
    public JSONObject robotCredit(@RequestBody JSONObject jsonObject , HttpServletRequest request) {
        _log.info("接收robotCredit加帐：" + jsonObject);
        JSONObject result = new JSONObject();
        // 判断请求IP是否允许+"："
        String clintIp = IPUtility.getClientIp(request);
        _log.info("请求ip为：" + clintIp);
//        boolean isAllow = PayUtil.ipAllow(clintIp, "8.218.60.174", "");
//        if (!isAllow) {
//            _log.info( "IP[" + clintIp + "]不允许访问");
//            result.put("code","12001");
//            result.put("msg","当前ip不支持");
//            return result;
//        }
        Long userId = Long.valueOf(jsonObject.getString("sfUserId"));
        SysUser sysUser = rpcCommonService.rpcSysService.findByUserId(userId);
        if (sysUser == null) {
            result.put("code","11011");
            result.put("msg","账户不存在");
            return result;
        }
        if (MchConstant.PUB_YES != sysUser.getStatus()) {
            result.put("code","13003");
            result.put("msg","用户禁止使用");
            return result;
        }

        Long mchId = Long.valueOf(jsonObject.getString("mchId"));
        String bizItem = "11";
        String amount = jsonObject.getString("amount");         // 变更金额,前端填写的为元,可以为小数点2位
        Long amountL = new BigDecimal(amount.trim()).multiply(new BigDecimal(100)).longValue(); // // 转成分
        String orderId = jsonObject.getString("orderId");
        String remark = jsonObject.getString("remark");
        // 判断输入的超级密码是否正确
//        String password = jsonObject.getString("password");
//        if(!"DF772266RT".equals(password)) {
//            result.put("code","-1");
//            result.put("msg","加款失败");
//            return result;
//        }

        try {
            //更换资金余额表的更新方式 rpcCommonService.rpcMchAccountService.credit2Account(mchId, MchConstant.BIZ_TYPE_CHANGE_BALANCE, amountL, bizItem);
            rpcCommonService.rpcMchAccountService.changeBalanceAndInsertHistoryByPlat(mchId, amountL, bizItem, orderId, remark);
            result.put("code","0");
            result.put("msg","加款成功");
            return result;
        }catch (ServiceException e) {
            _log.error(e, "");
            result.put("code","-1");
            result.put("msg","加款失败");
            return result;
        }catch (Exception e) {
            _log.error(e, "");
            result.put("code","-1");
            result.put("msg","加款失败");
            return result;
        }

    }

    @PostMapping("/robotDebit")
    public JSONObject robotDebit(@RequestBody JSONObject jsonObject , HttpServletRequest request) {
        _log.info("接收robotDebit下帐：" + jsonObject);
        JSONObject result = new JSONObject();
        // 判断请求IP是否允许+"："
        String clintIp = IPUtility.getClientIp(request);
        _log.info("请求ip为：" + clintIp);
//        boolean isAllow = PayUtil.ipAllow(clintIp, "8.218.60.174", "");
//        if (!isAllow) {
//            _log.info( "IP[" + clintIp + "]不允许访问");
//            result.put("code","12001");
//            result.put("msg","当前ip不支持");
//            return result;
//        }
        Long userId = Long.valueOf(jsonObject.getString("sfUserId"));
        SysUser sysUser = rpcCommonService.rpcSysService.findByUserId(userId);
        if (sysUser == null) {
            result.put("code","11011");
            result.put("msg","账户不存在");
            return result;
        }
        if (MchConstant.PUB_YES != sysUser.getStatus()) {
            result.put("code","13003");
            result.put("msg","用户禁止使用");
            return result;
        }

        Long mchId = Long.valueOf(jsonObject.getString("mchId"));
        String bizItem = "11";
        String amount = jsonObject.getString("amount");         // 变更金额,前端填写的为元,可以为小数点2位
        Long amountL = new BigDecimal(amount.trim()).multiply(new BigDecimal(100)).longValue(); // // 转成分
        String orderId = jsonObject.getString("orderId");
        String remark = jsonObject.getString("remark");
        // 判断输入的超级密码是否正确
//        String password = jsonObject.getString("password");
//        if(!"DF772266RT".equals(password)) {
//            result.put("code","-1");
//            result.put("msg","加款失败");
//            return result;
//        }

        try {
            //更换资金余额表的更新方式 rpcCommonService.rpcMchAccountService.credit2Account(mchId, MchConstant.BIZ_TYPE_CHANGE_BALANCE, amountL, bizItem);
            rpcCommonService.rpcMchAccountService.changeBalanceAndInsertHistoryByPlat(mchId, (0 - amountL), bizItem, orderId, remark);
            result.put("code","0");
            result.put("msg","下帐成功");
            return result;
        }catch (ServiceException e) {
            _log.error(e, "");
            result.put("code","-1");
            result.put("msg","下帐失败");
            return result;
        }catch (Exception e) {
            _log.error(e, "");
            result.put("code","-1");
            result.put("msg","下帐失败");
            return result;
        }

    }

}
